package dungeonPackage;

import static org.junit.Assert.*;

import java.util.*;

import org.junit.*;

import squareBorderPackage.*;

/**
 * A class collecting tests for the class of orientations.
 * 
 * @author Jessa Bekker & Esther Alberts
 * @version 1.0
 */
public class OrientationTest {

	/**
	 * Class variables referencing orientations that do not change during the
	 * entire test case.
	 */
	private static Orientation defaultOrientation, neighborNorth, neighborEast,
			neighborSouth, neighborWest, neighborCeiling, neighborFloor,
			noNeighbor, equalOrientation;

	/**
	 * Class variables referencing direction arrays that do not change during
	 * the entire test case.
	 */
	private static Direction[] directionsNorth, directionsEast,
			directionsSouth, directionsWest, directionsCeiling,
			directionsFloor;

	/**
	 * Set up an immutable test fixture.
	 * 
	 * @post The variable defaultOrientation references a new orientation
	 *       (10,20,30).
	 * @post The variable neighbor references a new orientation (9,20,30).
	 * @post The variable noNeighbor references a new orientation (8,20,30).
	 * @post The variable equalOrientation references a new orientation
	 *       (10,20,30).
	 * @post The variable direction references an array of size 2 with West as
	 *       its first direction and East as its second direction.
	 */
	@BeforeClass
	public static void setUpBeforeClass() {
		defaultOrientation = new Orientation(10, 20, 30);
		neighborNorth = new Orientation(10, 21, 30);
		neighborEast = new Orientation(11, 20, 30);
		neighborSouth = new Orientation(10, 19, 30);
		neighborWest = new Orientation(9, 20, 30);
		neighborCeiling = new Orientation(10, 20, 31);
		neighborFloor = new Orientation(10, 20, 29);
		noNeighbor = new Orientation(8, 20, 30);
		equalOrientation = new Orientation(10, 20, 30);
		directionsNorth = new Direction[2];
		directionsNorth[0] = Direction.NORTH;
		directionsNorth[1] = Direction.SOUTH;
		directionsEast = new Direction[2];
		directionsEast[0] = Direction.EAST;
		directionsEast[1] = Direction.WEST;
		directionsSouth = new Direction[2];
		directionsSouth[0] = Direction.SOUTH;
		directionsSouth[1] = Direction.NORTH;
		directionsWest = new Direction[2];
		directionsWest[0] = Direction.WEST;
		directionsWest[1] = Direction.EAST;
		directionsCeiling = new Direction[2];
		directionsCeiling[0] = Direction.CEILING;
		directionsCeiling[1] = Direction.FLOOR;
		directionsFloor = new Direction[2];
		directionsFloor[0] = Direction.FLOOR;
		directionsFloor[1] = Direction.CEILING;

	}

	@Test
	public void initializeObject_LegalCase() {
		Orientation orientation = new Orientation(5, 4, 3);
		assertTrue(orientation.getX() == 5 && orientation.getY() == 4
				&& orientation.getZ() == 3);
	}

	@Test(expected = IllegalArgumentException.class)
	public void initializeObject_IllegalCaseX() throws Exception {
		Orientation orientation = new Orientation(-50, 10, 30);
	}

	@Test(expected = IllegalArgumentException.class)
	public void initializeObject_IllegalCaseY() throws Exception {
		Orientation orientation = new Orientation(50, -10, 30);
	}

	@Test(expected = IllegalArgumentException.class)
	public void initializeObject_IllegalCaseZ() throws Exception {
		Orientation orientation = new Orientation(50, 10, -30);
	}

	@Test
	public void isValidCoordinate_LegalCase() {
		assertTrue(Orientation.isValidCoordinate(50));
	}

	@Test
	public void isValidCoordinate_Negative() {
		assertFalse(Orientation.isValidCoordinate(-50));
	}

	@Test
	public void isValidCoordinate_TooBig() {
		assertFalse(Orientation.isValidCoordinate(Long.MAX_VALUE + 50));
	}

	@Test
	public void isValidCoordinate_Zero() {
		assertTrue(Orientation.isValidCoordinate(0));
	}

	@Test
	public void isValidCoordinate_Max() {
		assertTrue(Orientation.isValidCoordinate(Long.MAX_VALUE));
	}

	@Test
	public void getX() {
		assertTrue(defaultOrientation.getX() == 10);
	}

	@Test
	public void getY() {
		assertTrue(defaultOrientation.getY() == 20);
	}

	@Test
	public void getZ() {
		assertTrue(defaultOrientation.getZ() == 30);
	}

	@Test
	public void getTangentOrientations() {
		Set<Orientation> neighbors = defaultOrientation
				.getTangentOrientations();
		assertTrue(neighbors.size() == 6
				&& neighbors.contains(new Orientation(9, 20, 30))
				&& neighbors.contains(new Orientation(11, 20, 30))
				&& neighbors.contains(new Orientation(10, 19, 30))
				&& neighbors.contains(new Orientation(10, 21, 30))
				&& neighbors.contains(new Orientation(10, 20, 29))
				&& neighbors.contains(new Orientation(10, 20, 31)));
	}

	@Test
	public void isTangentTo_True() {
		assertTrue(defaultOrientation.isTangentTo(neighborNorth));
	}

	@Test
	public void isTangentTo_False() {
		assertFalse(defaultOrientation.isTangentTo(noNeighbor));
	}

	@Test(expected = IllegalArgumentException.class)
	public void isTangentTo_IllegalCase() throws Exception {
		boolean neighbor = defaultOrientation.isTangentTo(null);
	}

	@Test
	public void getSharedBorderDirections_LegalCaseNorth() {
		Direction[] directions2 = defaultOrientation
				.getSharedBorderDirections(neighborNorth);
		assertTrue(directions2[0].equals(directionsNorth[0])
				&& directions2[1].equals(directionsNorth[1]));
	}

	@Test
	public void getSharedBorderDirections_LegalCaseEast() {
		Direction[] directions2 = defaultOrientation
				.getSharedBorderDirections(neighborEast);
		assertTrue(directions2[0].equals(directionsEast[0])
				&& directions2[1].equals(directionsEast[1]));
	}

	@Test
	public void getSharedBorderDirections_LegalCaseSouth() {
		Direction[] directions2 = defaultOrientation
				.getSharedBorderDirections(neighborSouth);
		assertTrue(directions2[0].equals(directionsSouth[0])
				&& directions2[1].equals(directionsSouth[1]));
	}

	@Test
	public void getSharedBorderDirections_LegalCaseWest() {
		Direction[] directions2 = defaultOrientation
				.getSharedBorderDirections(neighborWest);
		assertTrue(directions2[0].equals(directionsWest[0])
				&& directions2[1].equals(directionsWest[1]));
	}

	@Test
	public void getSharedBorderDirections_LegalCaseCeiling() {
		Direction[] directions2 = defaultOrientation
				.getSharedBorderDirections(neighborCeiling);
		assertTrue(directions2[0].equals(directionsCeiling[0])
				&& directions2[1].equals(directionsCeiling[1]));
	}

	@Test
	public void getSharedBorderDirections_LegalCaseFloor() {
		Direction[] directions2 = defaultOrientation
				.getSharedBorderDirections(neighborFloor);
		assertTrue(directions2[0].equals(directionsFloor[0])
				&& directions2[1].equals(directionsFloor[1]));
	}

	@Test(expected = IllegalArgumentException.class)
	public void getSharedBorderDirections_Null() throws Exception {
		Direction[] directions2 = defaultOrientation
				.getSharedBorderDirections(null);
	}

	@Test(expected = IllegalArgumentException.class)
	public void getSharedBorderDirections_noNeighbors() throws Exception {
		Direction[] directions2 = defaultOrientation
				.getSharedBorderDirections(noNeighbor);
	}

	@Test(expected = IllegalArgumentException.class)
	public void isOutside_IllegalCase() throws Exception {
		defaultOrientation.isOutside(null);
	}

	@Test
	public void isOutside_inside() {
		assertFalse(defaultOrientation.isOutside(neighborEast));
	}

	@Test
	public void isOutside_outsideX() {
		assertTrue(defaultOrientation.isOutside(neighborWest));
	}

	@Test
	public void isOutside_outsideY() {
		assertTrue(defaultOrientation.isOutside(neighborSouth));
	}

	@Test
	public void isOutside_outsideZ() {
		assertTrue(defaultOrientation.isOutside(neighborFloor));
	}

	@Test
	public void equals_Null() {
		assertFalse(defaultOrientation.equals(null));
	}

	@Test
	public void equals_otherClass() {
		assertFalse(defaultOrientation.equals(directionsNorth));
	}

	@Test
	public void equals_sameClassNotEqual() {
		assertFalse(defaultOrientation.equals(neighborNorth));
	}

	@Test
	public void equals_sameClassEqual() {
		assertTrue(defaultOrientation.equals(equalOrientation));
	}

	@Test
	public void getHashCode() {
		assertTrue(defaultOrientation.hashCode() == 60);
	}

	@Test
	public void getString() {
		assertTrue(defaultOrientation.toString().equals("(10,20,30)"));
	}

}
